package com.hera.process.config.service.impl;

import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.hera.base.util.Constantes;
import com.hera.base.util.FiltroDTO;
import com.hera.process.config.dao.ConditionDao;
import com.hera.process.config.dao.JdbcCoreDao;
import com.hera.process.config.dao.ProcessDao;
import com.hera.process.config.dao.ProcessInstanceDao;
import com.hera.process.config.dao.StageDao;
import com.hera.process.config.dao.StageUserDao;
import com.hera.process.config.dao.TaskInstanceCacheDao;
import com.hera.process.config.dao.TaskUserDao;
import com.hera.process.config.domain.Condition;
import com.hera.process.config.service.ProcessInstanceService;
import com.hera.process.security.domain.User;
import com.hera.process.workflow.domain.Process;
import com.hera.process.workflow.domain.ProcessInstance;
import com.hera.process.workflow.domain.Stage;
import com.hera.process.workflow.domain.StageUser;
import com.hera.process.workflow.domain.TaskInstanceCache;
import com.hera.process.workflow.domain.TaskUser;

@Service("processinstanceservice")
public class ProcessInstanceServiceImpl implements ProcessInstanceService {

	static final Logger logger = Logger.getLogger(CalendarServiceImpl.class);

	
	@Autowired
	private ProcessInstanceDao processinstancedao;
	@Autowired
	private ProcessDao processDao;
	@Autowired
	private StageDao stageDao;
	@Autowired
	private StageUserDao stageUserDao;
	@Autowired
	private TaskUserDao taskUserDao;
	@Autowired
	private TaskInstanceCacheDao taskInstanceCacheDao;
	@Autowired
	private JdbcCoreDao jdbcCoreDao;
	@Autowired
	private ConditionDao conditionDao;
	
	@Override
	public ProcessInstance findById(Long id) {
		
		return processinstancedao.findOne(id);
	}

	@Override
	public void update(ProcessInstance entity) {
		
		processinstancedao.save(entity);
	}

	@Override
	public void save(ProcessInstance entity) {
		
		processinstancedao.save(entity);
	}

	@Override
	public void delete(ProcessInstance entity) {
		
		processinstancedao.delete(entity);
	}

	@Override
	public List<ProcessInstance> findAll() {
		
		return processinstancedao.findAll();
	}

	@Override
	public List<ProcessInstance> findAll(FiltroDTO filtroDTO) {
		
		return processinstancedao.obtenerEntidadesPorFiltros(filtroDTO);
	}
	
	@Override
	public ProcessInstance createProcessInstance(Stage stage){
		
		//Guardando la instancia del proceso
		Process process = processDao.findOne(stage.getIdProcess());
		ProcessInstance processInstance = new ProcessInstance();
		processInstance.setProcess(process);
		//Traer el id del sgte stage
		Stage nextStage = stageDao.findNextStage(stage.getIdStage());
		processInstance.setIdCurrentStage(nextStage.getIdStage());
		
		processInstance.setName(process.getName());
		//processInstance.setStartUser(startUser);
		processInstance.setDescription(process.getDescription());
		//Traer el id del usuario de prioridad 1 de sgte stage
		List<StageUser> lstStageUser = stageUserDao.findByStageIdStageOrderByPriorityAsc(nextStage.getIdStage());
		User nextUser = null;
		//TODO para revisar cuando la asignacion en de otro tipo, GRUPO o Departamento
		if(lstStageUser.get(0).getType().getIdParameterDetail().equals(Constantes.TipoStageUser.USUARIO)){
			nextUser = lstStageUser.get(0).getUser();
			
		}
		processInstance.setCurrentUser(nextUser.getIdUser());
		processinstancedao.save(processInstance);
		
		//Guardando la tarea para el usuario
		TaskUser taskUser = new TaskUser();
		taskUser.setUser(nextUser);
		taskUser.setProcessInstance(processInstance);
		taskUser.setIdStage(nextStage.getIdStage());
		taskUser.setIdStatus(Constantes.ESTADOTAREA.PENDIENTE);
		
		taskUser.setName(nextStage.getName());
		taskUserDao.save(taskUser);
		
		TaskInstanceCache taskInstanceCache = new TaskInstanceCache();
		taskInstanceCache.setIdProcessInstance(processInstance.getIdProcessInstance());
		taskInstanceCache.setIdProcess(process.getIdProcess());
		taskInstanceCache.setTaskName(nextStage.getName());
		taskInstanceCache.setCurrentUser1(nextUser.getIdUser());
		taskInstanceCache.setIdStatus(Constantes.ESTADOTAREA.PENDIENTE);
		taskInstanceCache.setIdTask(taskUser.getIdTask());
		taskInstanceCache.setProcessName(process.getName());
		taskInstanceCache.setIdStage(nextStage.getIdStage());
		
		taskInstanceCacheDao.save(taskInstanceCache);
		
		return processInstance;
	}
	
	@Override
	public ProcessInstance createProcessInstance(Stage stage, Map<String, Object> entity){
		
		//Guardando la instancia del proceso
		Process process = processDao.findOne(stage.getIdProcess());
		ProcessInstance processInstance = new ProcessInstance();
		processInstance.setProcess(process);
		//Traer el id del sgte stage
		Stage nextStage = stageDao.findNextStage(stage.getIdStage());
		processInstance.setIdCurrentStage(nextStage.getIdStage());
		
		processInstance.setName(process.getName());
		//processInstance.setStartUser(startUser);
		processInstance.setDescription(process.getDescription());
		//Traer el id del usuario de prioridad 1 de sgte stage
		List<StageUser> lstStageUser = stageUserDao.findByStageIdStageOrderByPriorityAsc(nextStage.getIdStage());
		User nextUser = null;
		//TODO para revisar cuando la asignacion en de otro tipo, GRUPO o Departamento
		if(lstStageUser.get(0).getType().getIdParameterDetail().equals(Constantes.TipoStageUser.USUARIO)){
			nextUser = lstStageUser.get(0).getUser();
			
		}
		processInstance.setCurrentUser(nextUser.getIdUser());
		processinstancedao.save(processInstance);
		
		//insertando la metada		
		Long identity = jdbcCoreDao.insert(entity, "WORKFLOW2", "TBL_ABC");
		
		//Guardando la tarea para el usuario
		TaskUser taskUser = new TaskUser();
		taskUser.setUser(nextUser);
		taskUser.setProcessInstance(processInstance);
		taskUser.setIdStage(nextStage.getIdStage());
		taskUser.setIdStatus(Constantes.ESTADOTAREA.PENDIENTE);
		
		taskUser.setName(nextStage.getName());
		taskUser.setIdExtReference(identity);
		taskUserDao.save(taskUser);
		
		TaskInstanceCache taskInstanceCache = new TaskInstanceCache();
		taskInstanceCache.setIdProcessInstance(processInstance.getIdProcessInstance());
		taskInstanceCache.setIdProcess(process.getIdProcess());
		taskInstanceCache.setTaskName(nextStage.getName());
		taskInstanceCache.setCurrentUser1(nextUser.getIdUser());
		taskInstanceCache.setIdStatus(Constantes.ESTADOTAREA.PENDIENTE);
		taskInstanceCache.setIdTask(taskUser.getIdTask());
		taskInstanceCache.setProcessName(process.getName());
		taskInstanceCache.setIdStage(nextStage.getIdStage());
		taskInstanceCache.setIdExtReference(identity);
		
		taskInstanceCacheDao.save(taskInstanceCache);
		
		
		
		return processInstance;
	}
	
	
	@Override
	public ProcessInstance udpateProcessInstance(TaskInstanceCache taskInstanceCache, Map<String, Object> entity){
		//Obtenemos la instancia del proceso
		ProcessInstance processInstance = processinstancedao.findOne(taskInstanceCache.getIdProcessInstance());
		//Traer el id del sgte stage
		Stage nextStage = stageDao.findNextStage(taskInstanceCache.getIdStage());
		if(nextStage.getIdType().equals(Constantes.NODETYPE.ID_DECISION)){
			
			FiltroDTO filtroDTO = new FiltroDTO();
			filtroDTO.addParametro("stageRollup.stageFrom.idStage", nextStage.getIdStage());
			filtroDTO.addOrdenamientoAscendente("secuence");
			
			List<Condition> listConditions = conditionDao.obtenerEntidadesPorFiltros(filtroDTO);
			if(listConditions != null){
				for(int i=0; i<listConditions.size(); i++){
					Condition condition = listConditions.get(i);
					Object operandoLeft = null;
					if(condition.getTypeLeft().equals(Constantes.TIPO_OPERANDO_CONDICION.OPERANDO_VARIABLE)){
						//buscar con el id el valor para hacer el test de la condicion
						//Long idValue = condition.getValueLeft();
						
					}else if(condition.getTypeLeft().equals(Constantes.TIPO_OPERANDO_CONDICION.OPERANDO_FIJO)){
						operandoLeft = condition.getValueLeft();
						
					}
				}				
			}
		}
		
		if(nextStage.getIdType().equals(Constantes.NODETYPE.ID_END)){
			//Actualizar el processinstance, para cerrar la instancia del proceso, y los datos de atencion y tiempos
			processinstancedao.save(processInstance);
			
			//actualizando la metadata
			jdbcCoreDao.updateById(taskInstanceCache.getIdExtReference(), entity, "WORKFLOW2", "TBL_ABC");
			
			//Cerramos la tarea actual.
			TaskUser taskUserOld = taskUserDao.findOne(taskInstanceCache.getIdTask());
			taskUserOld.setIdStatus(Constantes.ESTADOTAREA.ATENDIDO);
			
			taskUserDao.save(taskUserOld);
			taskInstanceCacheDao.delete(taskInstanceCache);
			
		}else{
			processInstance.setIdCurrentStage(nextStage.getIdStage());
			
			//Traer el id del usuario de prioridad 1 de sgte stage
			List<StageUser> lstStageUser = stageUserDao.findByStageIdStageOrderByPriorityAsc(nextStage.getIdStage());
			User nextUser = null;
			//TODO para revisar cuando la asignacion en de otro tipo, GRUPO o Departamento
			if(lstStageUser.get(0).getType().getIdParameterDetail().equals(Constantes.TipoStageUser.USUARIO)){
				nextUser = lstStageUser.get(0).getUser();
				
			}
			processInstance.setCurrentUser(nextUser.getIdUser());
			processinstancedao.save(processInstance);
			
			//actualizando la metadata
			jdbcCoreDao.updateById(taskInstanceCache.getIdExtReference(), entity, "WORKFLOW2", "TBL_ABC");
							
			//Guardando la nueva tarea para el usuario
			TaskUser taskUser = new TaskUser();
			taskUser.setUser(nextUser);
			taskUser.setProcessInstance(processInstance);
			taskUser.setIdStage(nextStage.getIdStage());
			taskUser.setIdStatus(Constantes.ESTADOTAREA.PENDIENTE);
			
			taskUser.setName(nextStage.getName());
			taskUser.setIdExtReference(taskInstanceCache.getIdExtReference());
			taskUserDao.save(taskUser);
			
			TaskInstanceCache taskInstanceCacheN = new TaskInstanceCache();
			taskInstanceCacheN.setIdProcessInstance(processInstance.getIdProcessInstance());
			taskInstanceCacheN.setIdProcess(taskInstanceCache.getIdProcess());
			taskInstanceCacheN.setTaskName(nextStage.getName());
			taskInstanceCacheN.setCurrentUser1(nextUser.getIdUser());
			taskInstanceCacheN.setIdStatus(Constantes.ESTADOTAREA.PENDIENTE);
			taskInstanceCacheN.setIdTask(taskUser.getIdTask());
			taskInstanceCacheN.setProcessName(taskInstanceCache.getProcessName());
			taskInstanceCacheN.setIdStage(nextStage.getIdStage());
			taskInstanceCacheN.setIdExtReference(taskInstanceCache.getIdExtReference());
			
			taskInstanceCacheDao.save(taskInstanceCacheN);
			
			//Cerrando la tarea actual.
			TaskUser taskUserOld = taskUserDao.findOne(taskInstanceCache.getIdTask());
			taskUserOld.setIdStatus(Constantes.ESTADOTAREA.ATENDIDO);
			
			taskUserDao.save(taskUserOld);
			taskInstanceCacheDao.delete(taskInstanceCache);
		
		}
		return processInstance;
	}

}
